using System.Collections.Generic;
using Tycho.Compiler;

namespace Tycho.Runtime {
    public class ModuleManifest : IModuleScopeLoader {
        public List<IModuleLoader> ModuleLoaders { get; private set; }
        private Dictionary<Namespace, AnyObject> Modules;
        private ModuleFrameObject ModuleFrame;

        public ModuleManifest (ModuleFrameObject moduleFrame) {
            ModuleLoaders = new List<IModuleLoader> ();
            Modules = new Dictionary<Namespace, AnyObject> ();
            ModuleFrame = moduleFrame;
        }

        HashSet<Symbol> IModuleScopeLoader.LoadModule (Namespace ns) {
            AnyObject module = FindModule (ns);

            if (module != null) {
                return ModuleSymbolScope.GetVariableNames (module, ns);
            } else {
                return null;
            }
        }

        AnyObject FindModule (Namespace ns) {
            AnyObject module;

            if (!Modules.TryGetValue (ns, out module)) {
                foreach (IModuleLoader loader in ModuleLoaders) {
                    if (ns.IsDecendentOf (loader.BaseNamespace)) {
                        module = loader.LoadModule (ns, new NonRecursiveModuleLoader (ns, this));
                        Modules.Add (ns, module);
                        ModuleFrame.AddModule (module);
                        return module;
                    }
                }

                return null;
            }

            return module;
        }
    }

    public class NonRecursiveModuleLoader : IModuleScopeLoader {
        private Namespace NamespaceToBlock;
        private IModuleScopeLoader Loader;

        public NonRecursiveModuleLoader (Namespace namespaceToBlock, IModuleScopeLoader loader) {
            NamespaceToBlock = namespaceToBlock;
            Loader = loader;
        }

        public HashSet<Symbol> LoadModule (Namespace ns) {
            if (ns != NamespaceToBlock) {
                return Loader.LoadModule (ns);
            } else {
                return null;
            }
        }
    }
}